﻿#include "GUICreateSEABeamSelectPicklDialog.h"
#include "ui_GUICreateSEABeamSelectPicklDialog.h"

#include "FITK_Kernel/FITKCore/FITKActionOperator.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"

#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysBeam.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGeometryData.h"

#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelOperLine.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeomTools.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelPoint.h"

// Pick
#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "PickDataProvider/PickedData.h"

#include <QButtonGroup>
#include <QRegExpValidator>
#include <QTabBar>
#include <QMessageBox>

namespace GUI {

    GUICreateSEABeamSelectPicklDialog::GUICreateSEABeamSelectPicklDialog(Core::FITKActionOperator* oper, QWidget* parent /*= nullptr*/) :
        GUIDialogBase(parent),
        _oper(oper),
        _ui(new Ui::GUICreateSEABeamSelectPicklDialog)
    {
        _ui->setupUi(this);
        // 设置对话框关闭时自动删除
        setAttribute(Qt::WA_DeleteOnClose);
        //去掉问号
        Qt::WindowFlags flags = windowFlags();
        flags &= ~Qt::WindowContextHelpButtonHint;
        setWindowFlags(flags);
        //初始化界面
        _ui->lineEdit_x->setValidator(new QRegExpValidator(QRegExp("^-?(\\d+(\\.\\d+)?)$")));
        _ui->lineEdit_y->setValidator(new QRegExpValidator(QRegExp("^-?(\\d+(\\.\\d+)?)$")));
        _ui->lineEdit_z->setValidator(new QRegExpValidator(QRegExp("^-?(\\d+(\\.\\d+)?)$")));
        this->init();
        //获取拾取器，绑定拾取结束信号
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        //清除拾取对象所有的连接
        QObject::disconnect(pickProvider, SIGNAL(sig_pickedOver()), nullptr, nullptr);
        if (pickProvider)
        {
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedOver, this, &GUICreateSEABeamSelectPicklDialog::pickFinished);
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedData, this, &GUICreateSEABeamSelectPicklDialog::pickDataFinished);
        }
        //设置窗口自适应隐藏组件
        this->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
    }

    GUICreateSEABeamSelectPicklDialog::~GUICreateSEABeamSelectPicklDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    Acoustics::FITKSEASubSysBeam * GUICreateSEABeamSelectPicklDialog::getBeamData()
    {
        return _beamData;
    }

    void GUICreateSEABeamSelectPicklDialog::on_radioButton_Node_clicked(bool checked)
    {
        _ui->label_Picked->setText(QString("Picked (%1)"));
        _orientationPoint = false;
        if (!checked) return;
        _ui->groupBox->setEnabled(false);
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJDiscNode;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEABeamSelectPicklDialog::on_radioButton_Geometry_clicked(bool checked)
    {
        _ui->label_Picked->setText(QString("Picked (0)"));
        _orientationPoint = false;
        if (!checked) return;
        _ui->groupBox->setEnabled(true);
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJGeometryEdge;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEABeamSelectPicklDialog::on_radioButton_Mesh_clicked(bool checked)
    {
        _ui->label_Picked->setText(QString("Picked (%1)"));
        _orientationPoint = false;
        if (!checked) return;
        _ui->groupBox->setEnabled(true);
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJMeshCell1D;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEABeamSelectPicklDialog::on_pushButton_Pick_clicked(bool checked)
    {
        if (!checked) return;
        _orientationPoint = true;
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        if (_ui->radioButton_Geometry->isChecked())
            pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJDiscNode;
        else if (_ui->radioButton_Geometry->isChecked())
            pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJGeometryVert;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEABeamSelectPicklDialog::on_pushButton_Cancel_clicked()
    {
        this->reject();
    }

    void GUICreateSEABeamSelectPicklDialog::on_pushButton_OK_clicked()
    {
        //获取子系统管理器
        Acoustics::FITKAcousticsSEASubSysManager* subSysMgr = _SEAModel->getSEASubSysManager();
        if (!_oper || !subSysMgr) return;
        //清理数据
        if (_beamData)
            delete _beamData;
        _beamData = nullptr;
        //创建数据
        _beamData = new Acoustics::FITKSEASubSysBeam;
        //通过点创建梁
        if (_ui->radioButton_Node->isChecked())
        {
            if (!this->createBeamByNode())
                return;
        }
        //通过几何创建梁
        else if (_ui->radioButton_Geometry->isChecked())
        {
            if (!this->createBeamByGeometry())
                return;
        }
        //通过网格创建梁
        else if (_ui->radioButton_Mesh->isChecked())
        {
            if (!this->createBeamByMesh())
                return;
        }
        //更新几何属性
        _beamData->updateGeoProp();
        subSysMgr->appendDataObj(_beamData);
        _oper->setArgs("DataID", _beamData->getDataObjectID());

        this->accept();
    }

    bool GUICreateSEABeamSelectPicklDialog::createBeamByNode()
    {
        if (!_beamData) return false;
        //获取三维可视化对象管理
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return false;

        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        //设置点数据
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> nodes;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            nodes.append(pickData->getPickedDiscNodes());
        }
        if (nodes.size() < 3)
        {
            QMessageBox::warning(this, "", tr("Create Beam err! The number of nodes is not less than 3."), QMessageBox::Ok);
            return false;
        }
        nodes[0]._type = Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNodeType::Start;

        _beamData->setNodes(nodes);
        return true;
    }

    bool GUICreateSEABeamSelectPicklDialog::createBeamByGeometry()
    {
        if (!_beamData) return false;
        //获取三维可视化对象管理和几何数据
        Interface::FITKGeoCommandList *comList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider || !comList)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        if (pickList.isEmpty()) {
            QMessageBox::warning(this, "", tr("Create Beam err! The geometry Line data picked is 0."), QMessageBox::Ok);
            return false;
        }
        GraphData::PickedData* pickDataP = pickList.at(0);
        if (pickDataP == nullptr)return false;
        QList<int> pickedIds = pickDataP->getPickedIds();
        int DataObjId = pickDataP->getPickedDataObjId();
        if (pickedIds.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Create Beam err! The geometry Line data picked is 0."), QMessageBox::Ok);
            return false;
        }
        //获取方向点
        double xyz[3]{ 0,0,0 };
        xyz[0] = _ui->lineEdit_x->text().toDouble();
        xyz[1] = _ui->lineEdit_y->text().toDouble();
        xyz[2] = _ui->lineEdit_z->text().toDouble();
        //更新梁单元
        Interface::FITKAbsGeoCommand*comP = comList->getDataByID(DataObjId);
        if (!_beamData->updateBeam(comP, pickedIds.at(0), xyz))
        {
            QMessageBox::warning(this, "", tr("Create Beam err! Triangle patch error generated."), QMessageBox::Ok);
            return false;
        }
        return true;
    }

    bool GUICreateSEABeamSelectPicklDialog::createBeamByMesh()
    {
        if (!_beamData) return false;
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        //设置网格单元数据
        QHash<int, QList<int>> meshs;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            GraphData::PickedDataType pickType = pickData->getPickedDataType();
            if (GraphData::PickedDataType::MeshCellPick == pickType)
            {
                //获取partID和单元Id
                int partID = pickData->getPickedDataObjId();
                QList<int> faceElemsID = pickData->getPickedIds();
                if (faceElemsID.isEmpty()) continue;
                meshs.insert(partID, faceElemsID);
            }
        }
        if (meshs.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Create Beam err! The number of meshs is not less than 0."), QMessageBox::Ok);
            return false;
        }
        //获取方向点
        double xyz[3]{ 0,0,0 };
        xyz[0] = _ui->lineEdit_x->text().toDouble();
        xyz[1] = _ui->lineEdit_y->text().toDouble();
        xyz[2] = _ui->lineEdit_z->text().toDouble();
        if (!_beamData->updateBeam(meshs, xyz))
        {
            QMessageBox::warning(this, "", tr("Create Beam err! Picked meshs err."), QMessageBox::Ok);
            return false;
        }
        Acoustics::FITKAbstractSEAFace* faceData = _beamData->getFaceObj();
        if (faceData)
            faceData->setFEFace(true);
        return false;
    }

    void GUICreateSEABeamSelectPicklDialog::reject()
    {
        //清除拾取模式和高亮
        GUI::GUIPickInfo::ClearPickInfo();
        this->QDialog::reject();
    }

    void GUICreateSEABeamSelectPicklDialog::init()
    {
        //获取子系统类型
        if (!_oper)return;
        _oper->argValue<int>("SEASubSysType", _subSysType);
        _ui->lineEdit_x->setText("1");
        _ui->lineEdit_y->setText("0");
        _ui->lineEdit_z->setText("0");
        //初始化界面
        _ui->radioButton_Node->setChecked(true);
        this->on_radioButton_Node_clicked(true);
    }

    void GUICreateSEABeamSelectPicklDialog::pickFinished()
    {
        if (_orientationPoint)
        {
            //获取三维可视化对象管理
            GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
            if (!pickProvider)return;
            //获取拾取数据对象
            QList<int> geoNodeIds;
            QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> discNodeIds;
            QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
            for (GraphData::PickedData* pickData : pickList) {
                if (pickData == nullptr)continue;
                geoNodeIds = pickData->getPickedIds();
                discNodeIds = pickData->getPickedDiscNodes();
            }
            std::array<double, 3> xyz{ 0,0,0 };
            //获取点的数据并设置拾取模式
            GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
            if (_ui->radioButton_Geometry->isChecked() && geoNodeIds.isEmpty())
            {
                pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJGeometryEdge;
                xyz = this->getGeometryPointXYZ(geoNodeIds.at(0));
            }
            //获取离散点的数据
            else if (_ui->radioButton_Mesh->isChecked() && discNodeIds.isEmpty())
            {
                pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJMeshCell1D;
                xyz = this->getDiscModelPointXYZ(geoNodeIds.at(0));
            }
            //设置点的数据
            _ui->lineEdit_x->setText(QString::number(xyz.at(0), 'f', 7));
            _ui->lineEdit_y->setText(QString::number(xyz.at(1), 'f', 7));
            _ui->lineEdit_z->setText(QString::number(xyz.at(2), 'f', 7));
            pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
            GUI::GUIPickInfo::SetPickInfo(pickInfo);
        }
        else
        {
            this->on_pushButton_OK_clicked();
        }
    }

    std::array<double, 3> GUICreateSEABeamSelectPicklDialog::getGeometryPointXYZ(int id)
    {
        std::array<double, 3> xyz = { 1,0,0 };
        //获取几何工厂
        Interface::FITKInterfaceGeometryFactory*factory = Interface::FITKInterfaceGeometryFactory::getInstance();
        if (factory == nullptr)return xyz;
        //获取几何工具生成器
        Interface::FITKAbstractGeomToolsCreator*createor = factory->getGeomToolsCreator();
        if (!createor) return xyz;
        Interface::FITKAbstractGeomPointTool *pointTool = createor->createPointTool();
        if (!pointTool) return xyz;
        //获取节点坐标
        double pointArray[3];
        pointTool->getXYZ(id, pointArray);
        xyz.at(0) = pointArray[0];
        xyz.at(1) = pointArray[1];
        xyz.at(2) = pointArray[2];
        //释放节点工具
        delete pointTool;
        return xyz;
    }

    std::array<double, 3> GUICreateSEABeamSelectPicklDialog::getDiscModelPointXYZ(int id)
    {
        std::array<double, 3> xyz = { 1,0,0 };
        if (!_DiscModel) return xyz;
        //获取节点数据
        Acoustics::FITKAcousticsDiscNodeList* nodeList = _DiscModel->getNodes();
        if (!nodeList) return xyz;
        Core::FITKNode* node = nodeList->getNodeByID(id);
        if (!node) return xyz;
        //获取节点坐标
        double pointArray[3];
        node->getCoor(pointArray);
        xyz.at(0) = pointArray[0];
        xyz.at(1) = pointArray[1];
        xyz.at(2) = pointArray[2];
        return xyz;
    }

    void GUICreateSEABeamSelectPicklDialog::pickDataFinished()
    {
        //获取三维可视化对象管理
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return;
        QList<int> objIDList;
        int size = 0;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            objIDList.append(pickData->getPickedDataObjId());
            size = pickData->getPickedDiscNodes().size();
        }
        if (_ui->radioButton_Node->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(size));
        else if (_ui->radioButton_Geometry->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(objIDList.size()));
        else if (_ui->radioButton_Mesh->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(objIDList.size()));
    }
}
